﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Infrastructure.Base.Utils
{
    public static class EntityHelper
    {
        public static DataTable RowToColumn<TEnum, TType, TProperty>(Expression<Func<TType, TProperty>> groupBy,
            List<TType> items, string groupbyColumnCaption, string columnProperty, string valueProperty)
            where TEnum : struct
            where TType : class
        {
            var dt = new DataTable();
            string groupByColunmName = ((MemberExpression) groupBy.Body).Member.Name;
            List<PropertyInfo> properties = typeof (TType).GetProperties().ToList();


            //添加分组属性的数据类型，用于显示的时候序列化
            PropertyInfo tmp = properties.First(property => property.Name == groupByColunmName);
            dt.Columns.Add(new DataColumn(tmp.Name) {Caption = groupbyColumnCaption, DataType = tmp.PropertyType});

            EnumHelper.GetValueAndDescriptions<TEnum>().ForEach(item =>
            {
                {
                    if (item.Value != null)
                        dt.Columns.Add(new DataColumn(item.Key.ToString()) {Caption = item.Value});
                }
            });
            items.GroupBy(groupBy.Compile())
                .ToList()
                .ForEach(data =>
                {
                    DataRow dr = dt.NewRow();
                    data.ToList().ForEach(item =>
                    {
                        PropertyInfo groupByColunm =
                            properties.FirstOrDefault(property => property.Name == groupByColunmName);
                        PropertyInfo column = properties.FirstOrDefault(property => property.Name == columnProperty);
                        PropertyInfo value = properties.FirstOrDefault(property => property.Name == valueProperty);
                        if (column == null) return;
                        object columnValue = column.GetValue(item, null);
                        if (groupByColunm != null)
                        {
                            dr[groupByColunmName] = groupByColunm.GetValue(item, null).ToString();
                        }
                        if (columnValue != null && dt.Columns.Contains(columnValue.ToString()))
                            dr[columnValue.ToString()] = value == null || value.GetValue(item, null) == null
                                ? string.Empty
                                : value.GetValue(item, null).ToString();
                    });
                    dt.Rows.Add(dr);
                });
            return dt;
        }


        private static string FixDefaultValue(object obj)
        {
            if (obj == null)
                return string.Empty;
            if (obj.ToString() == default(decimal).ToString())
                return string.Empty;
            if (obj.ToString() == default(DateTime).ToString())
                return string.Empty;
            return obj.ToString();
        }


        public static string ToString<T>(this IEnumerable<T> items, string str) where T : class
        {
            var builder = new StringBuilder();
            items.ToList().ForEach(item => builder.AppendFormat("{0}{1}", str, item));
            builder.Remove(0, str.Length);
            return builder.ToString();
        }

        public static string GetClassDescription(Type type)
        {
            object[] item = type.GetCustomAttributes(typeof (DescriptionAttribute), false);
            return item.Length != 0 ? ((DescriptionAttribute) item[0]).Description : string.Empty;
        }

        #region 获取类属性的特性相关

        /// <summary>
        ///     递归获取类的属性的特性集合
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<TAttribute> GetPropertiesAttributesRecursion<TAttribute>(Type type)
            where TAttribute : Attribute
        {
            var list = new List<TAttribute>();

            type.GetProperties().ToList().ForEach(
                item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    if (attributes.Length != 0)
                        list.Add((TAttribute) attributes[0]);
                    //递归获取特性
                    if (item.ReflectedType.IsClass)
                        list.AddRange(GetPropertiesAttributesRecursion<TAttribute>(item.PropertyType));
                });


            return list;
        }

        /// <summary>
        ///     不递归获取类的特性的集合
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<TAttribute> GetPropertiesAttributes<TEntity, TAttribute>()
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof (TEntity).GetProperties().Select(
                item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    if (attributes.Length != 0)
                        return (TAttribute) attributes[0];
                    return null;
                }).Where(item => item != null).ToList();
        }

        /// <summary>
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <returns>key为属性的名字</returns>
        public static List<KeyValuePair<string, TAttribute>> GetPropertiesAttributesDict<TEntity, TAttribute>()
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof (TEntity).GetProperties().Select(
                item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    return new KeyValuePair<string, TAttribute>(item.Name,
                        attributes.Length != 0 ? (TAttribute) attributes[0] : null);
                }).Where(item => item.Value != null).ToList();
        }

        public static TAttribute GetPropertyAttribute<TEntity, TAttribute>(string propertyName)
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof (TEntity).GetProperties()
                .Where(item => item.Name == propertyName)
                .Select(item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    if (attributes.Length != 0)
                        return (TAttribute) attributes[0];
                    return default(TAttribute);
                }).First();
        }


        public static TAttribute GetPropertyAttribute<TAttribute>(Type type, string propertyName)
            where TAttribute : Attribute
        {
            return type.GetProperties()
                .Where(item => item.Name == propertyName)
                .Select(item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    if (attributes.Length != 0)
                        return (TAttribute) attributes[0];
                    return default(TAttribute);
                }).First();
        }


        /// <summary>
        ///     获取给定属性的特性
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TProperty"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="expression">属性表达式</param>
        /// <returns></returns>
        public static TAttribute GetPropertyAttribute<TEntity, TProperty, TAttribute>(
            Expression<Func<TEntity, TProperty>> expression)
            where TEntity : class
            where TAttribute : Attribute
        {
            var memberExpression = expression.Body as MemberExpression;
            return typeof (TEntity).GetProperties()
                .Where(item => memberExpression != null && item.Name == memberExpression.Member.Name)
                .Select(item =>
                {
                    object[] attributes = item.GetCustomAttributes(typeof (TAttribute), false);
                    if (attributes.Length != 0)
                        return (TAttribute) attributes[0];
                    return default(TAttribute);
                }).First();
        }

        #endregion
    }
}